import {
  Component,
  ViewChild,
  AfterViewInit,
  OnInit,
  OnDestroy,
  Output,
  EventEmitter,
  Inject
} from "@angular/core";
import { VERSION } from "@angular/material";
import { MatSelect } from "@angular/material";
import { ReplaySubject } from "rxjs";
import { Subject } from "rxjs";
import { take, takeUntil, skip } from "rxjs/operators";
import { LocaleService, TranslationService, Language } from "angular-l10n";
import { ActivatedRoute } from "@angular/router";

import { FormControl } from "@angular/forms";
import { forkJoin, combineLatest, zip } from "rxjs";
import { combineAll, debounceTime } from "rxjs/operators";
import { Router, NavigationEnd } from "@angular/router";

import { Store, select } from "@ngrx/store";
import * as fromAssets from "@/assets/store/reducers/index";
import * as fromUser from "@/user/store/reducers/index";
import * as fromRoot from "@/reducers/index";
import { map, filter } from "rxjs/operators";
import { Subscription } from "rxjs";
import { AssetsActions } from "@/assets/store/actions";
import { ISelectAssetsRequest } from "@/assets/store/models/assets";

@Component({
  selector: "app-coin-select",
  templateUrl: "./coin-select.component.html",
  styleUrls: ["./coin-select.component.scss"]
})
export class CoinSelectComponent implements OnInit, OnDestroy {
  version = VERSION;

  public select: FormControl = new FormControl();

  /** control for the MatSelect filter keyword */
  public selectFilter: FormControl = new FormControl();

  private lists: Array<any> = [];

  public filteredSelect: ReplaySubject<any[]> = new ReplaySubject<any[]>(1);

  @ViewChild("singleSelect") singleSelect: MatSelect;

  @Output()
  onChange: EventEmitter<any> = new EventEmitter();

  @Language() lang: string;

  /** Subject that emits when the component has been destroyed. */
  private _onDestroy = new Subject<void>();

  coinListsSub$: any;

  assetsLists$ = this.store
    .pipe(select(fromRoot.assetsLists))
    .pipe(filter(assetsLists => !!assetsLists));

  coinConfigLists$ = this.store
    .pipe(select(fromRoot.coinConfigLists))
    .pipe(filter(coinConfigLists => !!coinConfigLists));

  req: ISelectAssetsRequest = {
    uid: "",
    search: "",
    hideSmall: false
  };

  user$ = this.store.pipe(
    select(fromRoot.user),
    filter(user => !!user)
  );

  sub$ = {
    userSub$: null,
    assetsListsSub$: null,
    selectSub$: null,
    selectFilterSub$: null
  };

  constructor(
    private activatedRoute: ActivatedRoute,
    private router: Router,
    private store: Store<fromAssets.State | fromUser.State | fromRoot.State>,
    @Inject("UtilsService") private utilsService
  ) {}

  ngOnInit() {
    this.addListen();
  }

  addListen() {
    this.sub$.userSub$ = this.user$.subscribe(e => {
      // this.req.uid = e.id;
      this.store.dispatch(new AssetsActions.SelectAssets({ req: this.req }));
    });

    this.sub$.assetsListsSub$ = combineLatest(
      this.assetsLists$,
      this.activatedRoute.queryParams
    ).subscribe(([assetsLists, query]) => {
      this.lists = assetsLists;

      this.filteredSelect.next(this.lists.slice());

      const { coin } = query;
      if (!!coin) {
        this.lists.map(d => {
          if (coin.toLowerCase() === d.coin.toLowerCase()) {
            this.select.setValue(d);
          }
        });
      }
    });

    this.sub$.selectSub$ = this.select.valueChanges.subscribe(e => {
      this.onChange.emit(e);
    });

    // listen for search field value changes
    this.sub$.selectFilterSub$ = this.selectFilter.valueChanges
      .pipe(takeUntil(this._onDestroy))
      .subscribe(() => {
        this.filterSelect();
      });
  }

  ngOnDestroy() {
    this._onDestroy.next();
    this._onDestroy.complete();
    this.utilsService.unsub(this.sub$);
  }

  private filterSelect() {
    if (!this.lists) {
      return;
    }
    // get the search keyword
    let search = this.selectFilter.value;
    if (!search) {
      this.filteredSelect.next(this.lists.slice());
      return;
    } else {
      search = search.toLowerCase();
    }
    this.filteredSelect.next(
      this.lists.filter(item => item.coin.toLowerCase().indexOf(search) > -1)
    );
  }
}
